/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.zcp.notepad;

import com.zcp.notepad.NotePad.Notes;
import com.zcp.notepad.NotePad.Settings;
import com.zcp.notepad.NotePad.WidgetInfo;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;

public class NotePadProvider extends ContentProvider {

    private static final String TAG = "NotePadProvider";

    private static final String DATABASE_NAME = "notepad.db";

    private static final int DATABASE_VERSION = 1;

    private static final String NOTES_TABLE_NAME = "notes";

    private static final String SETTING_TABLE_NAME = "settings";

    private static final String WIDGET_TABLE_NAME = "widget";

    private static HashMap<String, String> sNotesProjectionMap;

    private static HashMap<String, String> sSettingsProjectionMap;

    private static HashMap<String, String> sWidgetInfoProjectionMap;

    private static final int NOTES = 1;

    private static final int NOTE_ID = 2;

    private static final int SETTINGS = 3;

    private static final int WIDGET = 4;

    private static final int WIDGET_ID = 5;

    private static final UriMatcher sUriMatcher;

    private static final String[] WIDGET_PROJECTION = new String[] {
            WidgetInfo.WIDGET_ID, // 0
            WidgetInfo.NOTE_ID, // 1
            WidgetInfo.WIDGET_SIZE, // 2
    };

    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (" + Notes._ID
                    + " INTEGER PRIMARY KEY," + Notes.TITLE + " TEXT," + Notes.NOTE + " TEXT,"
                    + Notes.COLOR + " TEXT," + Notes.LOCK + " INTEGER," + Notes.REMIND
                    + " INTEGER," + Notes.REMIND_TIME + " TEXT," + Notes.SHORTCUT_NAME + " TEXT,"
                    + Notes.TYPE + " INTEGER," + Notes.CREATED_DATE + " INTEGER,"
                    + Notes.MODIFIED_DATE + " INTEGER" + ");");

            db.execSQL("CREATE TABLE " + SETTING_TABLE_NAME + "(" + Settings._ID
                    + " INTEGER PRIMARY KEY," + Settings.PASSWORD + " TEXT" + ");");

            db.execSQL("CREATE TABLE " + WIDGET_TABLE_NAME + "(" + WidgetInfo._ID
                    + " INTEGER PRIMARY KEY," + WidgetInfo.WIDGET_ID + " INTEGER,"
                    + WidgetInfo.WIDGET_SIZE + " INTEGER," + WidgetInfo.NOTE_ID + " INTEGER" + ");");

        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion
                    + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS " + NOTES_TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + SETTING_TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + WIDGET_TABLE_NAME);
            onCreate(db);
        }
    }

    private DatabaseHelper mOpenHelper;

    @Override
    public boolean onCreate() {
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        switch (sUriMatcher.match(uri)) {
            case NOTES:
                qb.setProjectionMap(sNotesProjectionMap);
                qb.setTables(NOTES_TABLE_NAME);
                break;

            case NOTE_ID:
                qb.setProjectionMap(sNotesProjectionMap);
                qb.setTables(NOTES_TABLE_NAME);
                qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
                break;
            case SETTINGS:
                qb.setProjectionMap(sSettingsProjectionMap);
                qb.setTables(SETTING_TABLE_NAME);
                if (TextUtils.isEmpty(sortOrder)) {
                    sortOrder = "_ID DESC";
                }
                break;
            case WIDGET:
                qb.setProjectionMap(sWidgetInfoProjectionMap);
                qb.setTables(WIDGET_TABLE_NAME);
                if (TextUtils.isEmpty(sortOrder)) {
                    sortOrder = "_ID DESC";
                }
                break;
            case WIDGET_ID:
                qb.setProjectionMap(sWidgetInfoProjectionMap);
                qb.setTables(WIDGET_TABLE_NAME);
                qb.appendWhere(WidgetInfo.WIDGET_ID + "=" + uri.getPathSegments().get(1));
                if (TextUtils.isEmpty(sortOrder)) {
                    sortOrder = "_ID DESC";
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        // If no sort order is specified use the default
        String orderBy;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = Notes.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }

        // Get the database and run the query
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

        // Tell the cursor what uri to watch, so it knows when its source data
        // changes
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
            case NOTES:
                return Notes.CONTENT_TYPE;
            case NOTE_ID:
                return Notes.CONTENT_ITEM_TYPE;
            case SETTINGS:
                return Settings.CONTENT_TYPE;
            case WIDGET:
                return WidgetInfo.CONTENT_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        long rowId;
        Uri resultUri;
        switch (sUriMatcher.match(uri)) {
            case SETTINGS:
                rowId = db.insert(SETTING_TABLE_NAME, null, values);
                resultUri = ContentUris.withAppendedId(Settings.CONTENT_URI, rowId);
                getContext().getContentResolver().notifyChange(resultUri, null);
                return resultUri;
            case NOTES:
                Long now = Long.valueOf(System.currentTimeMillis());

                // Make sure that the fields are all set
                if (values.containsKey(Notes.CREATED_DATE) == false) {
                    values.put(Notes.CREATED_DATE, now);
                }

                if (values.containsKey(Notes.MODIFIED_DATE) == false) {
                    values.put(Notes.MODIFIED_DATE, now);
                }

                if (values.containsKey(Notes.TITLE) == false) {
                    Resources r = Resources.getSystem();
                    values.put(Notes.TITLE, r.getString(android.R.string.untitled));
                }

                if (values.containsKey(Notes.NOTE) == false) {
                    values.put(Notes.NOTE, "");
                }

                if (values.containsKey(Notes.NOTE) == false) {
                    values.put(Notes.LOCK, 0);
                }
                if (values.containsKey(Notes.REMIND) == false) {
                    values.put(Notes.REMIND, 0);
                }
                if (values.containsKey(Notes.REMIND_TIME) == false) {
                    values.put(Notes.REMIND_TIME, "0");
                }
                if (values.containsKey(Notes.SHORTCUT_NAME) == false) {
                    values.put(Notes.SHORTCUT_NAME, "0");
                }

                if (values.containsKey(Notes.COLOR) == false) {
                    values.put(Notes.COLOR, Notes.Color.ORANGE);
                }

                if (values.containsKey(Notes.TYPE) == false) {
                    values.put(Notes.TYPE, Notes.TYPE_TEXT);
                }

                rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
                if (rowId > 0) {
                    resultUri = ContentUris.withAppendedId(Notes.CONTENT_URI, rowId);
                    getContext().getContentResolver().notifyChange(resultUri, null);
                    return resultUri;
                }
            case WIDGET:
                rowId = db.insert(WIDGET_TABLE_NAME, null, values);
                if (rowId > 0) {
                    resultUri = ContentUris.withAppendedId(WidgetInfo.CONTENT_URI, rowId);
                    getContext().getContentResolver().notifyChange(resultUri, null);
                    return resultUri;
                }
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        Cursor widgetCursor;
        Intent intent;
        ArrayList<Intent> intentList = new ArrayList<Intent>();
        switch (sUriMatcher.match(uri)) {
            case NOTES:
                // 查询note所对应的widget
                Cursor c = db.query(NOTES_TABLE_NAME, new String[] {
                    Notes._ID
                }, where, whereArgs, null, null, null);

                if (c != null) {
                    // 把note所对应的widget信息封装进intent集合中

                    while (c.moveToNext()) {
                        int noteId = c.getInt(0);
                        widgetCursor = db.query(WIDGET_TABLE_NAME, WIDGET_PROJECTION,
                                WidgetInfo.NOTE_ID + "=" + noteId, null, null, null, null);
                        if (widgetCursor != null) {
                            intentList.clear();
                            while (widgetCursor.moveToNext()) {
                                intent = new Intent();
                                intent.setAction(NoteWidgetProvider.ACTION_UPDATE_BY_WIDGETID);
                                intent.putExtra("widget_id", widgetCursor.getInt(0));
                                // note_id设为-1，代表所对应的note已被删除
                                intent.putExtra("note_id", -1);
                                intent.putExtra("widget_size", widgetCursor.getInt(2));
                                intentList.add(intent);
                            }
                            widgetCursor.close();
                        }

                        db.delete(WIDGET_TABLE_NAME, WidgetInfo.NOTE_ID + "=" + noteId, null);

                    }
                    c.close();
                }
                count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
                // 发送广播让widget进行刷新
                for (Intent widgetInent : intentList) {
                    getContext().sendBroadcast(widgetInent);
                }
                break;

            case NOTE_ID:
                String noteId = uri.getPathSegments().get(1);
                // 先删除相关widget表的数据

                widgetCursor = db.query(WIDGET_TABLE_NAME, WIDGET_PROJECTION, WidgetInfo.NOTE_ID
                        + "=" + noteId, null, null, null, null);
                if (widgetCursor != null) {
                    intentList.clear();
                    while (widgetCursor.moveToNext()) {
                        intent = new Intent();
                        intent.setAction(NoteWidgetProvider.ACTION_UPDATE_BY_WIDGETID);
                        intent.putExtra("widget_id", widgetCursor.getInt(0));
                        // note_id设为-1，代表所对应的note已被删除
                        intent.putExtra("note_id", -1);
                        intent.putExtra("widget_size", widgetCursor.getInt(2));
                        intentList.add(intent);
                    }
                    widgetCursor.close();
                }
                db.delete(WIDGET_TABLE_NAME, WidgetInfo.NOTE_ID + "=" + noteId, null);
                count = db.delete(NOTES_TABLE_NAME,
                        Notes._ID + "=" + noteId
                                + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
                        whereArgs);
                // 发送广播让widget进行刷新
                for (Intent widgetInent : intentList) {
                    getContext().sendBroadcast(widgetInent);
                }
                break;
            case SETTINGS:
                count = db.delete(SETTING_TABLE_NAME, where, whereArgs);
                break;
            case WIDGET:
                count = db.delete(WIDGET_TABLE_NAME, where, whereArgs);
                break;
            case WIDGET_ID:
                String widgetId = uri.getPathSegments().get(1);
                count = db.delete(WIDGET_TABLE_NAME, WidgetInfo.WIDGET_ID + "=" + widgetId
                        + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        intentList.clear();
        intentList = null;
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri)) {
            case NOTES:
                count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
                
                //更新widget
                Cursor c = db.query(NOTES_TABLE_NAME, Notes.NOTE_PROJECTION, where, whereArgs,
                        null, null, null);
                if (c != null) {
                    while (c.moveToNext()) {
                        Util.updateWidget(getContext(), c.getInt(c.getColumnIndex(Notes._ID)));
                    }
                    c.close();
                }
                break;

            case NOTE_ID:
                String noteId = uri.getPathSegments().get(1);
                count = db.update(NOTES_TABLE_NAME, values,
                        Notes._ID + "=" + noteId
                                + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
                        whereArgs);
                Util.updateWidget(getContext(), Integer.parseInt(noteId));
                break;
            case SETTINGS:
                count = db.update(SETTING_TABLE_NAME, values, where, whereArgs);
                break;
            case WIDGET:
                count = db.update(WIDGET_TABLE_NAME, values, where, whereArgs);
                break;
            case WIDGET_ID:
                String widgetId = uri.getPathSegments().get(1);
                count = db.update(WIDGET_TABLE_NAME, values, WidgetInfo.WIDGET_ID + "=" + widgetId
                        + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
        sUriMatcher.addURI(NotePad.AUTHORITY, "settings", SETTINGS);
        sUriMatcher.addURI(NotePad.AUTHORITY, "widget", WIDGET);
        sUriMatcher.addURI(NotePad.AUTHORITY, "widget/#", WIDGET_ID);

        sSettingsProjectionMap = new HashMap<String, String>();
        sSettingsProjectionMap.put(Settings._ID, Settings._ID);
        sSettingsProjectionMap.put(Settings.PASSWORD, Settings.PASSWORD);

        sNotesProjectionMap = new HashMap<String, String>();
        sNotesProjectionMap.put(Notes._ID, Notes._ID);
        sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
        sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
        sNotesProjectionMap.put(Notes.COLOR, Notes.COLOR);
        sNotesProjectionMap.put(Notes.LOCK, Notes.LOCK);
        sNotesProjectionMap.put(Notes.REMIND, Notes.REMIND);
        sNotesProjectionMap.put(Notes.REMIND_TIME, Notes.REMIND_TIME);
        sNotesProjectionMap.put(Notes.SHORTCUT_NAME, Notes.SHORTCUT_NAME);
        sNotesProjectionMap.put(Notes.TYPE, Notes.TYPE);
        sNotesProjectionMap.put(Notes.CREATED_DATE, Notes.CREATED_DATE);
        sNotesProjectionMap.put(Notes.MODIFIED_DATE, Notes.MODIFIED_DATE);

        sWidgetInfoProjectionMap = new HashMap<String, String>();
        sWidgetInfoProjectionMap.put(WidgetInfo._ID, WidgetInfo._ID);
        sWidgetInfoProjectionMap.put(WidgetInfo.WIDGET_ID, WidgetInfo.WIDGET_ID);
        sWidgetInfoProjectionMap.put(WidgetInfo.WIDGET_SIZE, WidgetInfo.WIDGET_SIZE);
        sWidgetInfoProjectionMap.put(WidgetInfo.NOTE_ID, WidgetInfo.NOTE_ID);
    }
}
